import { Commit, createStore } from "vuex";
import { ColumnProps, GlobalDataProps, GlobalErrorProps, PostProps, UserProps } from "@/types";
import axios from '@/utils/http-utils';
import { objToArr, arrToObj } from "@/utils/Utils";
import { AxiosRequestConfig } from "axios";

const getAndCommit = async (url: string, mutationName: string, commit: Commit) => {
    const { data } = await axios.get(url);
    commit(mutationName, data);
    return data;
}

const postAndCommit = async (url: string, mutationName: string, commit: Commit, payload: any) => {
    const { data } = await axios.post(url, payload);
    commit(mutationName, data);
    return data;
}

const asyncAndCommit = async (url: string, mutationName: string,
    commit: Commit, config: AxiosRequestConfig = { method: 'get' }, extraData?: any) => {
    const { data } = await axios(url, config)
    if (extraData) {
        commit(mutationName, { data, extraData })
    } else {
        commit(mutationName, data)
    }
    return data
}

// vuex 解决的问题
// 解决组件树层层传递的问题
// 组件树向上触发数据传递的问题

const store = createStore<GlobalDataProps>({
    state: {
        token: localStorage.getItem('token') || '',
        columns: { data: {}, currentPage: 0, total: 0 },  // 专栏
        posts: { data: {}, loadedColumns: [] },    // 发布
        user: { isLogin: false },
        loading: false,
        error: { status: false }
    },
    // 必须同步调用
    mutations: {
        // login (state) {
        //     state.user = {...state.user, isLogin: true, name: 'Gorit'}
        // },
        createPost(state, newPost) {
            state.posts.data[newPost._id] = newPost;
        },
        fetchColumns(state, rawData) {
            const { data } = state.columns
            const { list, count, currentPage } = rawData.data
            state.columns = {
                data: { ...data, ...arrToObj(list) },
                total: count,
                currentPage: currentPage * 1
            }
        },
        fetchColumn(state, rawData) {
            state.columns.data[rawData.data._id] = rawData.data
        },
        fetchPosts(state, { data: rawData, extraData: columnId }) {
            state.posts.data = { ...state.posts.data, ...arrToObj(rawData.data.list) }
            state.posts.loadedColumns.push(columnId)
        },
        fetchPost(state, rawData) {
            state.posts.data[rawData.data._id] = rawData.data
        },
        deletePost(state, { data }) {
            delete state.posts.data[data._id]
        },
        updatePost(state, { data }) {
            state.posts.data[data._id] = data
        },
        setLoading(state, status) {
            state.loading = status
        },
        setError(state, e: GlobalErrorProps) {
            state.error = e;
        },
        fetchCurrentUser(state, rawData) {
            state.user = { isLogin: true, ...rawData.data };
        },
        login(state, rawData) {
            const { token } = rawData.data;
            state.token = token;
            localStorage.setItem('token', token);
            // 使用这个 common header 就不需要在 请求拦截器里面添加了
            axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
        },
        logout(state) {
            state.token = '';
            state.user = { isLogin: false };
            localStorage.removeItem('token');
            delete axios.defaults.headers.common.Authorization;
        }
    },
    actions: {
        fetchColumns({ state, commit }, params = {}) {
            // return getAndCommit('/api/columns', 'fetchColumns', ctx.commit);
            const { currentPage = 1, pageSize = 6 } = params
            // if (!state.columns.isLoaded) {
            //   return asyncAndCommit('/columns', 'fetchColumns', commit)
            // }
            if (state.columns.currentPage < currentPage) {
                return asyncAndCommit(`/api/columns?currentPage=${currentPage}&pageSize=${pageSize}`, 'fetchColumns', commit)
            }
        },
        fetchColumn({ state, commit }, cid: string) {
            if (!state.columns.data[cid]) {
                return asyncAndCommit(`/api/columns/${cid}`, 'fetchColumn', commit)
            }
            // return getAndCommit(`/api/columns/${cid}`, 'fetchColumn', commit);
        },
        fetchPosts({ state, commit }, cid: string) {
            // return getAndCommit(`/api/columns/${cid}/posts`, 'fetchPosts', commit);
            if (!state.posts.loadedColumns.includes(cid)) {
                return asyncAndCommit(`/api/columns/${cid}/posts`, 'fetchPosts', commit, { method: 'get' }, cid)
            }
        },
        fetchPost({ state, commit }, id) {
            const currentPost = state.posts.data[id]
            if (!currentPost || !currentPost.content) {
                return asyncAndCommit(`/api/posts/${id}`, 'fetchPost', commit)
            } else {
                return Promise.resolve({ data: currentPost })
            }
        },
        updatePost({ commit }, { id, payload }) {
            return asyncAndCommit(`/api/posts/${id}`, 'updatePost', commit, {
                method: 'patch',
                data: payload
            })
        },
        fetchCurrentUser({ commit }) {
            // return getAndCommit('/api/user/current', 'fetchCurrentUser', commit);
            return asyncAndCommit('/api/user/current', 'fetchCurrentUser', commit)
        },
        login({ commit }, payload) {
            // return postAndCommit('/api/user/login', 'login', commit, payload);
            return asyncAndCommit('/api/user/login', 'login', commit, { method: 'post', data: payload })
        },
        createPost({ commit }, payload) {
            // return postAndCommit('/api/posts', 'createPost', commit, payload);
            return asyncAndCommit('/api/posts', 'createPost', commit, { method: 'post', data: payload })
        },
        deletePost({ commit }, id) {
            return asyncAndCommit(`/api/posts/${id}`, 'deletePost', commit, { method: 'delete' })
          },
        loginAndFetch({ dispatch }, loginData) {
            return dispatch('login', loginData).then(() => {
                return dispatch('fetchCurrentUser')
            });
        }
    },
    // store 的计算属性
    getters: {
        getColumns: (state) => {
            return objToArr(state.columns.data)
        },
        getColumnById: (state) => (id: string) => {
            return state.columns.data[id]
        },
        getPostsByCid: (state) => (cid: string) => {
            return objToArr(state.posts.data).filter(post => post.column === cid)
        },
        getCurrentPost: (state) => (id: string) => {
            return state.posts.data[id]
        }
    }
});

// vuex 基本使用
// console.log(store.state.columns)
// store.commit('login');   // mutation 更新状态
// store.dispatch('fetchColumn', xxx)   // 调用 action
export default store;